package ar.edu.utn.frba.dds.tp.code.vuelos;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import ar.edu.utn.frba.dds.tp.code.Asientos.AsientoDeVuelo;
import ar.edu.utn.frba.dds.tp.code.Asientos.EstadoAsiento;
import ar.edu.utn.frba.dds.tp.code.usuarios.Usuario;
import ar.edu.utn.frba.dds.tp.code.usuarios.UsuarioStandard;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;


public abstract class Aerolinea{
	
	protected ArrayList<Vuelo> vuelos = new ArrayList<Vuelo>();
	
	public Aerolinea(){
		BuscadorVuelos elBuscador = BuscadorVuelos.getInstance();
		elBuscador.agregarAerolinea(this);
	}

	public abstract void comprarAsiento(AsientoDeVuelo asiento, Usuario comprador);
	public abstract List<Vuelo> vuelosDisponibles(Busqueda busqueda);
	
	public BigDecimal getImpuesto(){
		return new BigDecimal("0.00");
	}
	
	public ArrayList<Vuelo> getVuelos(){
		return this.vuelos;
	}
	
	public void reservarAsiento(AsientoDeVuelo asiento, UsuarioStandard reservante){
		throw new CantReserveException("La aerolinea no soporta reservas");
	}
	
	public  void handlerNuevaBusqueda(Busqueda busqueda){
		busqueda.addVuelos(this.vuelosDisponibles(busqueda));
	}
	
		
	protected void transferirReserva(AsientoDeVuelo asiento) {
		Vuelo vuelo = buscarVuelo(asiento);
		asiento = buscarAsiento(asiento, vuelo);
		agregarAsientoSiCorresponde(asiento, vuelo);
		UsuarioStandard reservante = asiento.primerSobreReservante();
		
		if(reservante != null){ //TODO: cuando modifique primerSobreReservante esto hay que cambiar tambien
			reservarAsiento(asiento, reservante);
		}
		else{
			asiento.setEstado(EstadoAsiento.DISPONIBLE);
			throw new CantReserveException("No existen reservantes");
		}
	}

	protected void ponerEnVuelo(AsientoDeVuelo asiento, ArrayList<Vuelo> vuelos) {
		
		Vuelo vuelo = buscarVuelo(asiento);
		vuelo.setAerolinea(this);
		asiento = buscarAsiento(asiento, vuelo);
		agregarAsientoSiCorresponde(asiento, vuelo);
		this.agregarVueloSiCorresponde(vuelo, vuelos);
	}

	private void agregarAsientoSiCorresponde(AsientoDeVuelo asiento, Vuelo vuelo) {
		if (!vuelo.getAsientos().contains(asiento)){
			vuelo.agregarAsiento(asiento);
			asiento.getVuelo().setAerolinea(this);
		}
	}

	private void agregarVueloSiCorresponde(Vuelo vuelo, ArrayList<Vuelo> vuelos) {
		if (!vuelos.contains(vuelo)){
			vuelos.add(vuelo);
		}
		if (!this.vuelos.contains(vuelo)){
			this.vuelos.add(vuelo);
		}
	}
	
	protected Vuelo buscarVuelo(final AsientoDeVuelo asiento) {
		//el predicado para el find
		Predicate<Vuelo> predicate = new Predicate<Vuelo>() {
	
			@Override
			public boolean apply(Vuelo vuelo) {
				return vuelo.equals(asiento.getVuelo());
			}
		};
		
		//find devuelve el vuelo que cumpla con la condición del apply o 
		//un vuelo nuevo con el número de asiento del asiento
				
		return Iterables.find(vuelos, predicate, asiento.getVuelo());
	}
	
	protected AsientoDeVuelo buscarAsiento(final AsientoDeVuelo asientoBuscado, Vuelo vuelo) {
		//el predicado para el find
		Predicate<AsientoDeVuelo> predicate = new Predicate<AsientoDeVuelo>() {
	
			@Override
			public boolean apply(AsientoDeVuelo asiento) {
				return asiento.equals(asientoBuscado);
			}
		};
		
		//find devuelve el asiento que cumpla con la condición del apply o 
		//el mismo asiento en caso de no haber ninguno
				
		return Iterables.find(vuelo.getAsientos(), predicate, asientoBuscado);
	}

}
